/*
 * @Author: yanjikun
 * @Date: 2022-04-12 17:51:12
 * @LastEditors: yanjikun
 * @LastEditTime: 2022-05-24 11:09:21
 * @Description: file content
 */

import { isFunction } from '@/utils/is'
import * as echarts from 'echarts'
import { nextTick, unref, watch } from 'vue'
import { BasicChartProps } from '../basic-chart'
import { ChartState } from './useChartState'
import { ECharts, EChartsOption } from 'echarts'
import { ChartThemeType } from '../types/chart'
import { useEventListener } from '@/hooks/event/useEventListener'
import { tryOnUnmounted, useDebounceFn } from '@vueuse/core'
import { useTimeoutFn } from '@/hooks/core/useTimeout'
import { isBoolean, isObject } from 'lodash'
import { error } from '@/utils/log'

export type ChartMethods = ReturnType<typeof useChartMethods>
export type UseChartMethodsContext = {
  state: ChartState
  props: BasicChartProps
}

export const useChartMethods = ({ state, props }: UseChartMethodsContext) => {
  const { loading, basicChartRef, chartOptions, enableShow } = state
  let chartInstance: ECharts | null = null
  let removeResizeFn: Fn = () => {}
  /**
   * @description:echarts图表缩放
   * @param {*}
   * @return {*}
   * @author: yanjikun
   */
  const resize = () => {
    chartInstance?.resize()
  }
  const resizeFn = useDebounceFn(resize, 200)
  /**
   * @description: echarts设置Option
   * @param {EChartsOption} option echarts的option
   * @param {*} clear 是否清除图表数据
   * @return {*}
   * @author: yanjikun
   */
  const setOption = (option: EChartsOption, clear = true) => {
    if (unref(basicChartRef)?.offsetHeight === 0) {
      useTimeoutFn(() => {
        setOption(option)
      }, 30)
      return
    }
    nextTick(() => {
      useTimeoutFn(() => {
        if (!chartInstance) {
          initChart(props.theme)
          if (!chartInstance) {
            return
          }
        }
        clear && (chartInstance as ECharts)?.clear()
        ;(chartInstance as ECharts)?.setOption(option)
      }, 30)
    })
  }
  /**
   * @description: 初始化echarts实例
   * @param {ChartThemeType} t echarts主题
   * @return {*}
   * @author: yanjikun
   */
  const initChart = (t: ChartThemeType = 'default') => {
    const basicChart = unref(basicChartRef)
    if (!basicChart || !unref(basicChart)) {
      error('未获取到chart实例！')
      return
    }
    chartInstance = echarts.init(basicChart, t)
    const { removeEvent } = useEventListener({ el: window, name: 'resize', listener: resizeFn })
    removeResizeFn = removeEvent
    if (basicChart.offsetHeight === 0) {
      useTimeoutFn(() => {
        resizeFn()
      }, 30)
    }
  }
  /**
   * @description: 获取echarts实例
   * @param {*}
   * @return {*} echarts实例
   * @author: yanjikun
   */
  const getInstance = (): Nullable<ECharts> => {
    if (!chartInstance) {
      initChart(props.theme)
    }
    return unref(chartInstance) as Nullable<ECharts>
  }
  /**
   * @description: 获取echarts的Option
   * @param {Recordable} params 后台接口传递的参数
   * @author: yanjikun
   */
  const fetchData = async (params: Recordable = {}) => {
    if (!Object.is(props.dataSource, undefined)) {
      setOption(unref(chartOptions))
      return
    }
    if (!(Object.is(props.dataSource, undefined) && isFunction(props.dataRequest))) {
      enableShow.value = false
      return
    }
    const queryParams = {
      ...params,
    }
    try {
      loading.value = true
      const data = await props?.dataRequest?.(queryParams).finally(() => {
        loading.value = false
      })
      if (isObject(data)) {
        enableShow.value = true
        setOption(data)
        chartOptions.value = data
      } else if (isBoolean(data)) {
        enableShow.value = false
        if (chartInstance) chartInstance.dispose()
      }
    } catch (error) {
      enableShow.value = false
    }
  }
  /**
   * @description: 刷新图表
   * @param {*}
   * @return {*}
   * @author: yanjikun
   */
  const reload = () => {
    fetchData()
  }
  watch(
    () => props.theme,
    (theme) => {
      if (chartInstance) {
        chartInstance.dispose()
        initChart(theme as 'default')
        setOption(chartOptions.value)
      }
    },
  )
  tryOnUnmounted(() => {
    if (!chartInstance) return
    removeResizeFn()
    chartInstance.dispose()
    chartInstance = null
  })
  return {
    reload,
    fetchData,
    getInstance,
    setOption,
    resize,
    chartInstance: chartInstance as ECharts | null,
  }
}
